package com.tbit.main.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tbit.common.constant.OperationPlatform;
import com.tbit.common.entity.MachineOpLog;
import com.tbit.common.entity.vo.MainLogAuditVo;
import com.tbit.main.constant.*;
import com.tbit.main.controller.interceptor.LoginUserContextHolder;
import com.tbit.main.dao.core.DispatchPayLogDao;
import com.tbit.main.dao.core.TagDao;
import com.tbit.main.dao.log.DispatchLogDao;
import com.tbit.main.exception.BaseException;
import com.tbit.main.h2.pojo.ParkPoint;
import com.tbit.main.pojo.*;
import com.tbit.main.pojo.bo.CommonControlParamBO;
import com.tbit.main.pojo.bo.TerControlBO;
import com.tbit.main.service.*;
import com.tbit.main.util.DateTimeUtil;
import com.tbit.main.util.GeoUtil;
import com.tbit.main.util.LogUtil;
import com.tbit.main.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.tbit.main.util.TimeUtil.dateDiff;

/**
 * 调度记录
 *
 * @author Leon
 * 2019年11月14日 下午10:37:52
 */
@Slf4j
@Service("dispatchLogService")
public class DispatchLogServiceImpl implements DispatchLogService {
    @Autowired
    private DispatchLogDao dispatchLogDao;
    @Autowired
    private DispatchPayLogDao dispatchPayLogDao;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ParkPointService parkPointService;
    @Autowired
    private MachineService machineService;
    @Autowired
    private TerControlService terControlService;
    @Autowired
    private AccountUserService accountUserService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private MachineOccupyService machineOccupyService;
    @Autowired
    private CalibrateService calibrateService;
    @Autowired
    private GeoreMachineService georeMachineService;
    @Autowired
    private GeoreGionService georeGionService;
    @Autowired
    private DataService dataService;
    @Autowired
    private RideLogService rideLogService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private VerticalParkLogService verticalParkLogService;
    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private WorkOrderFinishingService workOrderFinishingService;
    @Autowired
    private MachineFunctionService machineFunctionService;
    @Autowired
    private MachineOpLogService machineOpLogService;
    @Autowired
    private DispatchPerformanceService performanceService;
    @Autowired
    private TagDao tagDao;
    @Autowired
    private DispatchPerformanceService dispatchPerformanceService;
    @Autowired
    private AccountConfigExtService accountConfigExtService;

    @Override
    public Integer insert(DispatchLog dispatchLog) {
        Integer result = dispatchLogDao.insert(dispatchLog);

        AccountUser accountUser = LoginUserContextHolder.getLoginUser();

        // 插入车辆操作日志
        machineOpLogService.insertSingle(MachineOpLog.builder()
                .accountId(dispatchLog.getAccountId())
                .machineId(dispatchLog.getMachineId())
                .machineNO(dispatchLog.getMachineNO())
                .userCode(dispatchLog.getUserCode())
                .operation("调度")
                .opUser(accountUser.getName())
                .opUserPhone(accountUser.getPhone())
                .opPlatform(OperationPlatform.MAINTAIN.code)
                .result(true)
                .opTime(LocalDateTime.now())
                .build()
        );

        // 插入调度绩效
        dispatchPerformanceService.calculateAndInsertPerformance(dispatchLog);

        return result;
    }

    @Override
    public List<DispatchLogSta> groupByTime(Integer agentId, Integer userType, Integer usermainId, Integer state,
                                            String startTime, String endTime, Integer isValid, List<Integer> regionId, Integer machineType) {
        List<DispatchLogSta> dlses;

        /**查询代理商运维账号*/
        List<Integer> accountUserIds = new ArrayList<>();
        /**判断当前账号是不是运维人员*/
        if (roleService.getRoleCode(userType).equals(1)) {
            accountUserIds.add(usermainId);
        }

        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, agentId);
        params.put("userMainIds", StringUtil.getListString(accountUserIds));
        params.put("state", state);
        params.put("isValid", isValid);
        params.put(DaoParamConstant.startTime, startTime);
        params.put(DaoParamConstant.endTime, endTime);
        if (CollUtil.isEmpty(regionId)) {
            params.put("exist", "'exist'");
            regionId = georeGionService.getByAccountUserId(usermainId);
        } else {
            params.put("exist", null);
        }
        params.put("regionId", StringUtil.getListString(regionId));
        params.put("machineType", machineType);
        dlses = dispatchLogDao.groupByTime(params);

        List<Integer> userMainIds = dlses.stream().map(DispatchLogSta::getUserMainId).collect(Collectors.toList());
        Map<Integer, AccountUser> accountUserMap = accountUserService.getByIds(userMainIds)
                .stream().collect(Collectors.toMap(AccountUser::getAccountUserId, Function.identity()));

        List<DispatchLogSta> dlseFilters = new ArrayList<>();
        for (DispatchLogSta dls : dlses) {
            Optional.ofNullable(accountUserMap.get(dls.getUserMainId()))
                    .ifPresent(au -> {
                        dls.setName(au.getName());
                        dls.setPhone(au.getPhone());
                        dls.setDelFlag(au.getDelFlag());
                        dlseFilters.add(dls);
                    });
        }
        return dlseFilters;
    }

    @Override
    public List<DispatchLog> getByTime(Integer accountId, Integer userMainId, Integer state,
                                       String startTime, String endTime, String userCode, Integer isValid, List<Integer> regionId, Integer machineType) {
        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, accountId);
        params.put("userMainId", userMainId);
        params.put("state", state);
        params.put("isValid", isValid);
        params.put(DaoParamConstant.startTime, startTime);
        params.put(DaoParamConstant.endTime, endTime);
        if (CollUtil.isEmpty(regionId)) {
            params.put("exist", "'exist'");
            regionId = georeGionService.getByAccountUserId(userMainId);
        } else {
            params.put("exist", null);
        }
        params.put("regionId", StringUtil.getListString(regionId));
        params.put("machineType", machineType);
        params.put("userCode", userCode);

        return dispatchLogDao.getByTime(params);
    }

    @Override
    public DispatchLog dispatch(AccountUser accountUser, String machineNO,
                                Integer parkPointId, Double lon, Double lat, Integer mapType) throws Exception {
        Machine machine = machineService.getByMachineNO(machineNO);
        DispatchLog dispatchLog = null;

        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**判断车辆是否是调度申请车辆*/
        String userIdString = redisService.get(RedisConstant.MACHINE_DISPATCH_APPLY_LOG + machine.getMachineNO());
        if (userIdString != null) {
            Integer userId = Integer.valueOf(userIdString);
            if (!userId.equals(accountUser.getAccountUserId())) {
                /**删除redis记录*/
                redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH + machine.getMachineNO());
                /**删除批量redis记录,人员*/
                String userDispatchMachineCache = RedisConstant.REDIS_BATCH_DISPATCH + userId;
                redisService.delToList(userDispatchMachineCache, machine.getUserCode());
                /**删除批量redis记录,区域*/
                String areaDispatchMachineCache = RedisConstant.REDIS_BATCH_DISPATCH_AREA + machine.getAccountId();
                redisService.delToList(areaDispatchMachineCache, machine.getUserCode());

            }
        }

        AccountConfig accountConfig = dataService.getAccountConfig(machine.getAccountId());

        /**redis获取数据*/
        String dispatchLogString = null;
        try {
            dispatchLogString = redisService.get(RedisConstant.REDIS_TER_BIKE_DISPATCH + machineNO);
        } catch (SerializationException e) {
            redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH + machineNO);
        }


        /**批量获取redis数据,人员*/
        String userDispatchMachineCache = RedisConstant.REDIS_BATCH_DISPATCH + accountUser.getAccountUserId();
        /**批量获取redis数据,区域*/
        String areaDispatchMachineCache = RedisConstant.REDIS_BATCH_DISPATCH_AREA + machine.getAccountId();
        /**兼容调度申请，不需要进行调度前条件判断*/
        String apply = redisService.get(RedisConstant.MACHINE_DISPATCH_APPLY_LOG + machine.getMachineNO());

        if (dispatchLogString == null) {

            Integer value = dataService.getRoleConfig(accountUser.getAccountUserType() + RoleConfigConstant.MAIN_LOCK_VEHICLE);
            if (value != null && value.equals(1)) {
                /**运维占用最大数判断*/
                if (accountConfig != null && apply == null) {
                    if (accountConfig.getOccupyMax() != null && !accountConfig.getOccupyMax().equals(0)) {
                        Integer occupy = machineOccupyService.getByAccountUserId(accountUser.getAccountUserId());
                        if (occupy >= accountConfig.getOccupyMax()) {
                            throw new BaseException("Machine.occupyMax.exist");
                        }
                    }
                }
            }


            /**记录投放记录*/
            DispatchLog dl = new DispatchLog();
            dl.setAccountId(machine.getAccountId());
            dl.setUserMainId(accountUser.getAccountUserId());
            dl.setMachineId(machine.getMachineId());
            dl.setUserCode(machine.getUserCode());
            dl.setMachineNO(machine.getMachineNO());
            dl.setDispatchTime(DateTimeUtil.getNowTime());
            dl.setIdleTime(DateTimeUtil.getHours(machine.getLastBorrowTime(), DateTimeUtil.getNowTime()));
            dl.setState(0);
            dl.setIsValid(0);
            dl.setUserIdStartLon(lon);
            dl.setUserIdStartLat(lat);
            dl.setMachineType(machine.getMachineType());
            dl.setMapType(mapType);
            /**
             * 判断分区
             */
            GeoreMachine georeMachine = georeMachineService.getByMachineId(machine.getMachineId());
            if (georeMachine != null) {
                dl.setRegionId(georeMachine.getRegionId());
            }


            /**判断是否是禁停区*/
            AccountConfig ac = dataService.getAccountConfig(machine.getAccountId());
            if (ac != null && ac.getReturnModel() == 1) {
            } else {
                /** 重新判断站点 */
                MachineStatus mahcineStatus = dataService.getMachineStatus(machine.getMachineId());
                if (mahcineStatus != null) {
                    ParkPoint parkPointNEW = parkPointService.checkInParkPointNew(machine.getAccountId(), new Point(mahcineStatus.getLon(), mahcineStatus.getLat()), 50, null);
                    if (parkPointNEW != null) {
                        machineService.put(new ParkMachine(parkPointNEW.getParkPointId(), machine.getMachineId(), parkPointNEW.getInside()));
                    }
                }
            }

            /**查询车辆归属站点*/
            ParkPoint parkPoint = parkPointService.getByMachineId(machine.getMachineId());
            dl.setOldParkPoint(parkPoint == null ? "" : parkPoint.getName());
            dl.setOldParkPointId(parkPoint == null ? null : parkPoint.getParkPointId());
            redisService.add(RedisConstant.REDIS_TER_BIKE_DISPATCH + machineNO, JSONObject.toJSONString(dl), 3600 * 3);
            redisService.add(RedisConstant.REDIS_TER_BIKE_DISPATCHANDMOVE + machine.getMachineId(), parkPoint == null ? "" : parkPoint.getParkPointId() + "", 3600 * 3);


            // 排除新版单车不触发开锁业务
            if ((machine.getMachineType().equals(MachineTypeConstant.BIKE) && machineFunctionService.checkIsSendControl(machine.getMachineId()))
                    || machine.getMachineType().equals(MachineTypeConstant.ELECTRIC_BIKE)) {
                /**开锁*/
                TerControlBO terControl1 = new TerControlBO(ControlType.MACHINE_CONTROL_UNLOCK, "调度自动开锁");
                /**头盔锁发送强制开锁指令*/
                TerControlBO terControl2 = new TerControlBO(ControlType.MACHINE_CONTROL_COERCE_LOCK, "调度自动开锁-强制开锁");
                terControlService.batchControl(machine, ListUtil.of(terControl1, terControl2));
            }

            /**批量获取redis数据,人员*/
            List<String> userCode = new LinkedList<>();
            try {
                userCode = redisService.getList(userDispatchMachineCache);
            } catch (SerializationException e) {
                redisService.del(userDispatchMachineCache);
            }

            if (userCode == null || !userCode.contains(machine.getUserCode())) {
                /**批量添加到redis中*/
                redisService.andToList(userDispatchMachineCache, machine.getUserCode());
                LogUtil.info("添加3：" + userCode);
            }

            /**批量获取redis数据,区域*/
            List<String> userCodeDispatch = new LinkedList<>();
            try {
                userCodeDispatch = redisService.getList(areaDispatchMachineCache);
            } catch (SerializationException e) {
                redisService.del(areaDispatchMachineCache);
            }

            if (userCodeDispatch == null || !userCodeDispatch.contains(machine.getUserCode())) {
                /**批量添加到redis中*/
                redisService.andToList(areaDispatchMachineCache, machine.getUserCode());
            }

            /**记录运维事件轨迹*/
            try {
                TerPosition terPosition = new TerPosition();
                terPosition.setMachineNO(accountUser.getPhone());
                terPosition.setLat(lat);
                terPosition.setLon(lon);
                terPosition.setDt(DateTimeUtil.getNowTime());
                terPosition.setExData(HistoryExData.UW + "=" + HistoryExData.DD + ";");
                calibrateService.calTerPosition(terPosition, mapType, SysConstant.ORIGINAL);
                historyService.insert(terPosition);
            } catch (Exception e) {
                log.error("记录运维事件轨迹异常", e);
            }

            //记录垂直停车记录
            verticalParkLogService.updateEnable(machine.getMachineNO());

            redisService.add(RedisConstant.REDIS_TER_BIKE_DISPATCH_USER_CODE + machine.getUserCode(), machine.getMachineNO(), 3600 * 3);

            // 运维绩效-调度绩效需记录当前标签
            List<TagBaseInfo> currTags = tagDao.getTagByMachineId(machine.getMachineId());
            performanceService.cacheTags(machine.getMachineId(), currTags);

            // 运维绩效-记录当前车辆异常
            performanceService.cacheAbnormal(machine.getMachineId());
        } else {

            String dateTime = DateTimeUtil.getMinsAgo(5);
            try {
                dispatchLog = JSONObject.parseObject(dispatchLogString, DispatchLog.class);
            } catch (JSONException e) {
                redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH + machineNO);
            }

            if (parkPointId != null) {

                String newTime = DateTimeUtil.getNowTime();

                /**查询站点*/
                ParkPoint parkPoint = parkPointService.getByParkPointId(parkPointId);
                if (parkPoint == null) {
                    throw new BaseException("ParkPoint.notExist");
                }
                MachineStatus machineStatus = machineStatusService.getByMachineId(machine.getMachineId());

                if (machineStatus != null && DateTimeUtil.getTime(machineStatus.getPosDt(), DateTimeUtil.getNowTime()) <= 300) {
                    Double distance = GeoUtil.getDistance(new Point(lon, lat), new Point(machineStatus.getLon(), machineStatus.getLat()));
                    if (distance > 100) {
                        throw new BaseException("phone.distance.is.long");
                    }
                }

                dispatchLog.setFinishTime(newTime);
                dispatchLog.setNewParkPoint(parkPoint.getName());
                dispatchLog.setState(1);
                dispatchLog.setIsValid(1);
                dispatchLog.setUserIdEndLon(lon);
                dispatchLog.setUserIdEndLat(lat);
                dispatchLog.setAuditorId(1);

                dispatchLog.setNewParkPointId(parkPointId);
                dispatchLog.setUserMainId(accountUser.getAccountUserId());

                Integer distance;
                try {
                    Integer machineIdDt = machineStatusService.getByBatDtId(machine.getMachineId(), dateTime);
                    if (machineIdDt != null) {
                        TrajectoryBO trajectory = historyService.getTrajectoryByMachineNOAndTime(machine.getMachineNO(), dispatchLog.getDispatchTime(), dispatchLog.getFinishTime());
                        distance = trajectory.getDistance();
                        // 车辆轨迹距离
                        dispatchLog.setDistance(distance);
                        // 车辆直线距离
                        dispatchLog.setStraightDistance(trajectory.getStraightDistance());
                    } else {
                        Point pointS = new Point(dispatchLog.getUserIdStartLon(), dispatchLog.getUserIdStartLat());
                        Point pointE = new Point(dispatchLog.getUserIdEndLon(), dispatchLog.getUserIdEndLat());
                        pointS = calibrateService.commonCalibrate(pointS, mapType, SysConstant.ORIGINAL);
                        pointE = calibrateService.commonCalibrate(pointE, mapType, SysConstant.ORIGINAL);
                        distance = (int) GeoUtil.getDistance(pointS, pointE);
                    }
                } catch (Exception e) {
                    log.warn(e.getMessage(), e);
                    distance = 0;
                }

                // 调度前 24 小时内有效订单
                List<RideLog> rideLogs = rideLogService.getMachineIdStartTime(machine.getMachineId(), DateTimeUtil.getDayAgoTime(1), null);
                rideLogs = rideLogs.stream().filter(rideLog -> StrUtil.isNotBlank(rideLog.getEndTime())).collect(Collectors.toList());
                dispatchLog.setBeforeValidOrder(rideLogs.size());

                /** 判断是否有效调度 */
                DispatchConfig dispatchConfig = dataService.getDispatch(machine.getAccountId());
                boolean dispatchJudge = true;
                if (dispatchConfig != null) {
                    // 前置校验
                    String remark = dispatchPreconditionCheck(dispatchConfig, machine, dispatchLog, userIdString);
                    // 判断时间
                    if (!dispatchConfig.getDispatchTime().equals(0) && dispatchLog.getIsValid().equals(1)) {
                        long time = dateDiff(dispatchLog.getDispatchTime(), dispatchLog.getFinishTime(), "yyyy-MM-dd HH:mm:ss");
                        if (time < dispatchConfig.getDispatchTime().longValue()) {
                            dispatchLog.setIsValid(0);
                        }
                        remark = remark + dispatchLog.getUserCode() + "配置时间：" + dispatchConfig.getDispatchTime() + "，实际时间：" + (int) time;
                    }

                    // 判断站点
                    if (dispatchConfig.getSameParkPoint().equals(0) && dispatchLog.getIsValid().equals(1)) {
                        String parkPointIdRedis = redisService.get(RedisConstant.REDIS_TER_BIKE_DISPATCHANDMOVE + machine.getMachineId());
                        log.info("调度：旧站点 Id 缓存：{}，新站点 Id：{}", parkPointIdRedis, parkPointId);
                        if (parkPointIdRedis != null && !parkPointIdRedis.equals("") && parkPointId.equals(Integer.valueOf(parkPointIdRedis))) {
                            dispatchLog.setIsValid(0);
                        } else {
                            dispatchLog.setIsValid(1);
                        }
                        remark = remark + dispatchLog.getUserCode() + "配置站点：" + dispatchConfig.getSameParkPoint() + "，老站点：" + dispatchLog.getOldParkPoint() + "，新站点：" + parkPoint.getName() + (dispatchLog.getIsValid() == 1 ? ",有效" : ",无效") + ";";
                    }

                    // 判断距离
                    if (!dispatchConfig.getDispatchDistance().equals(0) && dispatchLog.getIsValid().equals(1)) {
                        if (distance == null || distance < dispatchConfig.getDispatchDistance()) {
                            dispatchLog.setIsValid(0);

                            dispatchJudge = false;
                            dispatchLog.setRemark(remark);
                            /**添加到redismap*/
                            redisService.set(RedisConstant.REDIS_TER_BIKE_DISPATCH_DISTANCE_CHANGE_MAP, machineNO, String.valueOf(System.currentTimeMillis()));
                            redisService.add(RedisConstant.REDIS_TER_BIKE_DISPATCH + machineNO, JSONObject.toJSONString(dispatchLog), 3600 * 3);
                            log.info("调度增加距离缓存" + machine.getUserCode());
                        } else {
                            dispatchLog.setIsValid(1);
                        }

                        remark = remark + dispatchLog.getUserCode() + "配置距离：" + dispatchConfig.getDispatchDistance() + "，实际距离：" + distance;
                        if (dispatchLog.getIsValid().equals(1)) {
                            remark = remark + "有效；";
                        } else {
                            remark = remark + "无效；";
                        }
                    }
                    if (dispatchJudge) {
                        Integer isValid = dispatchLog.getIsValid();
                        Integer state = WorkOrderConstant.state_WC;
                        // 判断订单时间
                        if (dispatchConfig.getRideTime() != null && dispatchConfig.getRideTime() != 0) {
                            state = WorkOrderConstant.state_SHZ;

                            String ordersAfterLastDispatchMachineKey = String.format(RedisConstant.ORDERS_AFTER_LAST_DISPATCH_MACHINE, machine.getMachineId());
                            int rideTimeSecond = dispatchConfig.getRideTime() * 60 * 60;
                            // 调度后产生订单时间动态配置缓存有效订单时长
                            redisService.add(ordersAfterLastDispatchMachineKey, StrPool.AT, rideTimeSecond);
                            log.info("记录调度后车辆({})有效订单", machine);
                        }
                        if (!state.equals(WorkOrderConstant.state_SHZ) || isValid.equals(0)) {
                            dispatchLog.setIsValid(isValid);
                            dispatchLog.setAuditTime(newTime);
                            state = WorkOrderConstant.state_WC;
                        } else {
                            dispatchLog.setIsValid(2);
                        }

                        dispatchLog.setRemark(remark);

                        insert(dispatchLog);

                        // 结束调度工单
                        String workOrderId = this.endWork(machine.getMachineId(), dispatchLog.getDispatchLogId(), dispatchLog.getIsValid(), state, accountUser, remark);

                        /**订单条件缓存*/
                        if (state.equals(WorkOrderConstant.state_SHZ) && isValid.equals(1)) {
                            PowerChangeRedis powerChangeRedis = new PowerChangeRedis();
                            powerChangeRedis.setPowerChangeId(dispatchLog.getDispatchLogId());
                            powerChangeRedis.setWorkOrderId(workOrderId);
                            powerChangeRedis.setRideTime(dispatchConfig.getRideTime());
                            powerChangeRedis.setTime(newTime);

                            List<PowerChangeRedis> powerChangeList = new LinkedList<>();
                            /**判断是否存在审核中*/
                            String powerChangeRedisList = redisService.get(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machine.getMachineNO());
                            if (powerChangeRedisList != null) {
                                List<PowerChangeRedis> powerChangeLogs = new LinkedList<>();
                                try {
                                    powerChangeLogs = JSON.parseArray(powerChangeRedisList, PowerChangeRedis.class);
                                } catch (JSONException e) {
                                    redisService.del(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machine.getMachineNO());
                                }

                                if (CollUtil.isNotEmpty(powerChangeLogs)) {
                                    powerChangeList.addAll(powerChangeLogs);
                                }
                            }
                            powerChangeList.add(powerChangeRedis);

                            /**订单判断缓存*/
                            redisService.add(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machine.getMachineNO(), JSONObject.toJSONString(powerChangeList), (3600 * dispatchConfig.getRideTime()) + 1200);
                            /**二级缓存*/
                            redisService.set(RedisConstant.REDIS_TER_BIKE_DISPATCH_CHANGE_RIDE_MAP, machine.getMachineNO(), String.valueOf(System.currentTimeMillis()));
                        }

                        /**修改最后借出时间*/
                        machineService.updateLastBorrowTime(machine.getMachineId());

                        /**投放车辆*/
                        try {
                            Integer inside = null;
                            if (machineStatus != null) {
                                Double distance1;
                                ParkPoint parkPoint1 = dataService.getParkPoint(parkPointId);
                                // 圆形站点
                                if (parkPoint1.getParkPointType().equals(0)) {
                                    distance1 = GeoUtil.getDistance(new Point(machineStatus.getLon(), machineStatus.getLat()), new Point(parkPoint1.getLo(), parkPoint1.getLa()));
                                } else {
                                    List<Point> points = dataService.getParkList(parkPointId);
                                    distance1 = GeoUtil.getDistance(new Point(machineStatus.getLon(), machineStatus.getLat()), points);
                                }
                                if (distance1 <= parkPoint1.getAllowRange()) {
                                    inside = 1;
                                } else {
                                    inside = 0;
                                }
                            }
                            Integer i = machineService.parkMachineInside(machine.getMachineId(), parkPoint.getParkPointId(), inside);
                            if (i == 0) {
                                machineService.put(new ParkMachine(parkPoint.getParkPointId(), machine.getMachineId(), inside));
                            }
                        } catch (Exception e) {
                            log.error("投放车辆异常 车辆id {},车辆编号{}", machine.getMachineId(), machine.getMachineNO(), e);
                        }

                        /**删除redis记录*/
                        redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH + machineNO);

                        /**删除调度申请标识*/
                        redisService.del(RedisConstant.MACHINE_DISPATCH_APPLY_LOG + machine.getMachineNO());
                    }

                    /**删除批量redis记录,人员*/
                    redisService.delToList(userDispatchMachineCache, machine.getUserCode());
                    /**删除批量redis记录,区域*/
                    redisService.delToList(areaDispatchMachineCache, machine.getUserCode());

                    /**上锁*/
                    dispatchLock(machine, "调度完成自动上锁");

                    updateAudit(machine.getMachineId(), dispatchLog, machine.getAccountId(), machine.getMachineNO());

                    redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH_USER_CODE + machine.getUserCode());
                }
            }
        }

        return dispatchLog;
    }

    private String dispatchPreconditionCheck(DispatchConfig dispatchConfig, Machine machine, DispatchLog dispatchLog, String userId) {
        if (StringUtils.isNotBlank(userId)) {
            log.info("调度申请车辆不进行前置校验 用户id" + userId + ",车辆编号:" + dispatchLog.getUserCode());
            return "";
        }
        if (StringUtils.isBlank(dispatchConfig.getCheckedCondition())) {
            return "";
        }
        log.info("调度时间" + dispatchLog.getDispatchTime() + "系统配置:" + dispatchConfig);
        if (dispatchConfig.getCheckedCondition() == null) {
            return "";
        }
        List<String> checkedCondition = Arrays.stream(dispatchConfig.getCheckedCondition().split(","))
                .collect(Collectors.toList());
        if (checkedCondition.isEmpty()) {
            return "";
        }
        boolean matchOne = dispatchConfig.matchOne();
        String remark = dispatchLog.getUserCode() + (matchOne ? ";[前置条件]满足任一:" : ";[前置条件]满足所有:");
        int failedConditionsCount = 0;
        // 配置时长校验
        if (checkedCondition.contains("0")) {
            // 闲置时长 如果未配置就是0
            Integer dispatchLeave = Optional.ofNullable(dispatchConfig.getDispatchLeave()).orElse(0);
            Integer time = DateTimeUtil.getHours(StringUtils.defaultIfBlank(machine.getLastBorrowTime(), DateTimeUtil.getNowTime()), DateTimeUtil.getNowTime());
            boolean checkResult = dispatchLeave <= time;
            if (!checkResult) {
                failedConditionsCount++;
            }
            log.info("调度时间" + dispatchLog.getDispatchTime() + "上次借车时间" + machine.getLastBorrowTime() + "相差" + time + "结果:" + checkResult);
            remark = remark + "配置时长:" + dispatchConfig.getDispatchLeave() + "，闲置时长:" + time + "," + (checkResult ? "有效;" : "无效;");
        }

        if (checkedCondition.contains("1") || checkedCondition.contains("2") || checkedCondition.contains("3")) {
            List<DispatchLog> dispatchLogs = getByMachineIdTime(machine.getMachineId(), null, 1);
            List<RideLog> rideLogs;
            if (CollectionUtils.isNotEmpty(dispatchLogs)) {
                rideLogs = rideLogService.getMachineIdStartTime(machine.getMachineId(), dispatchLogs.get(0).getDispatchTime(), null);
            } else {
                rideLogs = rideLogService.getMachineIdStartTime(machine.getMachineId(), null, dispatchLog.getFinishTime());
            }
            String orderNO = rideLogs.stream().max(Comparator.comparing(RideLog::getStartTime)).map(RideLog::getOrderNO).orElse(null);
            log.info(dispatchLog.getUserCode() + "调度记录" + JSON.toJSONString(dispatchLogs) + " 骑行订单" + JSON.toJSONString(rideLogs));
            if (checkedCondition.contains("1")) {
                // 上次调度后产生有效订单
                boolean needRideOrder = Objects.equals(1, dispatchConfig.getRide());

                if (needRideOrder && StrUtil.isBlank(orderNO)) {
                    failedConditionsCount++;
                    remark = remark + WorkOrderConstant.sys_ride_Valid;

                } else if (needRideOrder && StrUtil.isNotBlank(orderNO)) {
                    remark = remark + WorkOrderConstant.sys_ride_isValid + String.format(WorkOrderConstant.sys_ride_last_order, orderNO);
                } else {
                    remark = remark + "产生有效订单验证:关闭;";
                }
            }
            if (checkedCondition.contains("2")) {
                Integer logTime = Optional.ofNullable(dispatchConfig.getLogTime()).orElse(0);
                if (logTime <= 0) {
                    remark = remark + "配置间隔:" + logTime + "分钟,有效;";
                } else {
                    List<DispatchLog> dispatchLogList = getByMachineIdTime(machine.getMachineId(), DateTimeUtil.getMinsAgo(logTime), 1);
                    if (CollectionUtils.isNotEmpty(dispatchLogList)) {
                        failedConditionsCount++;
                        remark = remark + "距上次调度间隔未超过" + logTime + "分钟,无效;";
                    } else {
                        remark = remark + "配置间隔:" + logTime + "分钟,有效;";
                    }
                }
            }
            if (checkedCondition.contains("3")) {
                int rideDistance = Optional.ofNullable(dispatchConfig.getRideDistance()).orElse(0);
                remark = remark + "配置骑行:" + rideDistance + "米,";
                if (rideDistance > 0) {
                    double distanceCount = 0;
                    for (RideLog rideLog : rideLogs) {
                        distanceCount = distanceCount + rideLog.getMileage();
                    }
                    if ((distanceCount * 1000) >= rideDistance) {
                        remark = remark + "实际骑行:" + (distanceCount * 1000) + ",有效;";
                    } else {
                        failedConditionsCount++;
                        remark = remark + "实际骑行:" + (distanceCount * 1000) + ",无效;";
                    }
                } else {
                    remark = remark + "有效;";
                }
            }
        }
        boolean finalResult;
        if (matchOne) {
            finalResult = checkedCondition.size() != failedConditionsCount;
        } else {
            finalResult = failedConditionsCount == 0;
        }
        dispatchLog.setIsValid(finalResult ? 1 : 0);
        log.info("前置调度方法内dispatchLog {}", JSON.toJSONString(dispatchLog));
        if (StringUtils.isNotBlank(remark)) {
            remark = remark + "[前置条件]。";
        }
        log.info("前置条件调度最终结果：" + remark);
        return remark;
    }

    @Override
    public DispatchPaySta staByTime(Integer accountId, String startTime, String endTime) {

        Map<String, Object> params = new HashMap<>();
        params.put(DaoParamConstant.accountId, accountId);
        params.put(DaoParamConstant.startTime, startTime);
        params.put(DaoParamConstant.endTime, endTime);

        return dispatchPayLogDao.staByTime(params);
    }

    @Override
    public DispatchPaySta staRegionIdByTime(Integer regionId, String startTime, String endTime) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("regionId", regionId);
        params.put(DaoParamConstant.startTime, startTime);
        params.put(DaoParamConstant.endTime, endTime);
        return dispatchPayLogDao.staRegionIdByTime(params);
    }

    @Override
    public Integer getByAccountIdTime(Integer accountId, Integer state, String startTime, String endTime, Integer isValid) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put(DaoParamConstant.accountId, accountId);
        params.put("state", state);
        params.put("isValid", isValid);
        params.put(DaoParamConstant.startTime, startTime);
        params.put(DaoParamConstant.endTime, endTime);
        return dispatchLogDao.getByAccountIdTime(params);
    }

    @Override
    public Integer getByRegionIdTime(Integer regionId, Integer state, String startTime, String endTime, Integer isValid) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("regionId", regionId);
        params.put("state", state);
        params.put("isValid", isValid);
        params.put(DaoParamConstant.startTime, startTime);
        params.put(DaoParamConstant.endTime, endTime);
        return dispatchLogDao.getByRegionIdTime(params);
    }

    @Override
    public List<Map<String, Object>> getGroupByDay(Integer accountId, String statDate, String endDate) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put(DaoParamConstant.accountId, accountId);
        params.put("statDate", statDate);
        params.put("endDate", endDate);

        return dispatchLogDao.getGroupByDay(params);
    }


    @Override
    public void dispatchBatch(AccountUser accountUser, List<String> userCode, Integer parkPointId, Double lon, Double lat, Integer mapType) throws Exception {
        userCode = userCode.stream().distinct().collect(Collectors.toList());

        DispatchLog dispatchLog = null;

        List<Machine> machineList = machineService.getByUserCodes(userCode);

        String newTime = DateTimeUtil.getNowTime();
        for (Machine machine : machineList) {

            /**判断车辆是否是调度申请车辆*/
            String userIdString = redisService.get(RedisConstant.MACHINE_DISPATCH_APPLY_LOG + machine.getMachineNO());

            /**redis获取数据*/
            String dispatchLogString = redisService.get(RedisConstant.REDIS_TER_BIKE_DISPATCH + machine.getMachineNO());

            if (dispatchLogString != null) {
                String dateTime = DateTimeUtil.getMinsAgo(5);
                try {
                    dispatchLog = JSONObject.parseObject(dispatchLogString, DispatchLog.class);
                } catch (JSONException e) {
                    redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH + machine.getMachineNO());
                }

                /**查询站点*/
                ParkPoint parkPoint = parkPointService.getByParkPointId(parkPointId);
                if (parkPoint == null) {
                    throw new BaseException("ParkPoint.notExist");
                }

                dispatchLog.setFinishTime(newTime);
                dispatchLog.setNewParkPoint(parkPoint.getName());
                dispatchLog.setState(1);
                dispatchLog.setIsValid(1);
                dispatchLog.setUserIdEndLon(lon);
                dispatchLog.setUserIdEndLat(lat);
                dispatchLog.setAuditorId(1);

                dispatchLog.setNewParkPointId(parkPointId);
                dispatchLog.setUserMainId(accountUser.getAccountUserId());

                Integer distance = 0;
                try {
                    Integer machineIdDt = machineStatusService.getByBatDtId(machine.getMachineId(), dateTime);
                    if (machineIdDt != null) {
                        TrajectoryBO trajectory = historyService.getTrajectoryByMachineNOAndTime(machine.getMachineNO(), dispatchLog.getDispatchTime(), dispatchLog.getFinishTime());
                        distance = trajectory.getDistance();
                        // 车辆轨迹距离
                        dispatchLog.setDistance(distance);
                        // 车辆直线距离
                        dispatchLog.setStraightDistance(trajectory.getStraightDistance());
                    } else {
                        Double userIdStartLon = dispatchLog.getUserIdStartLon();
                        Double userIdStartLat = dispatchLog.getUserIdStartLat();
                        if (userIdStartLon != null && userIdStartLat != null) {
                            Point pointS = new Point(userIdStartLon, userIdStartLat);
                            Point pointE = new Point(dispatchLog.getUserIdEndLon(), dispatchLog.getUserIdEndLat());
                            pointS = calibrateService.commonCalibrate(pointS, mapType, SysConstant.ORIGINAL);
                            pointE = calibrateService.commonCalibrate(pointE, mapType, SysConstant.ORIGINAL);
                            distance = (int) GeoUtil.getDistance(pointS, pointE);
                        }
                    }
                } catch (Exception e) {
                    log.warn(e.getMessage(), e);
                }

                // 调度前 24 小时内有效订单
                List<RideLog> rideLogs = rideLogService.getMachineIdStartTime(machine.getMachineId(), DateTimeUtil.getDayAgoTime(1), null);
                rideLogs = rideLogs.stream().filter(rideLog -> StrUtil.isNotBlank(rideLog.getEndTime())).collect(Collectors.toList());
                dispatchLog.setBeforeValidOrder(rideLogs.size());

                /** 判断是否有效调度 */
                Integer isValid = 1;
                Integer state = WorkOrderConstant.state_WC;
                boolean dispatchJudge = true;
                DispatchConfig dispatchConfig = dataService.getDispatch(machine.getAccountId());

                if (dispatchConfig != null) {

                    String remark = dispatchPreconditionCheck(dispatchConfig, machine, dispatchLog, userIdString);
                    log.info("前置调度方法后dispatchLog {}", JSON.toJSONString(dispatchLog));

                    if (!dispatchConfig.getDispatchTime().equals(0) && dispatchLog.getIsValid().equals(1)) {
                        // 判断时间
                        Long time = dateDiff(dispatchLog.getDispatchTime(), dispatchLog.getFinishTime(), "yyyy-MM-dd HH:mm:ss");

                        if (time < dispatchConfig.getDispatchTime().longValue()) {
                            dispatchLog.setIsValid(0);
                        }
                        remark = remark + "配置时间：" + dispatchConfig.getDispatchTime() + "，实际时间：" + time.intValue() + ";";
                    }
                    // 判断站点
                    if (dispatchConfig.getSameParkPoint().equals(0) && dispatchLog.getIsValid().equals(1)) {
                        String parkPointIdRedis = redisService.get(RedisConstant.REDIS_TER_BIKE_DISPATCHANDMOVE + machine.getMachineId());
                        log.info("调度：旧站点 Id 缓存：{}，新站点 Id：{}", parkPointIdRedis, parkPointId);
                        if (parkPointIdRedis != null && !parkPointIdRedis.equals("") && parkPointId.equals(Integer.valueOf(parkPointIdRedis))) {
                            dispatchLog.setIsValid(0);
                        } else {
                            dispatchLog.setIsValid(1);
                        }
                        remark = remark + dispatchLog.getUserCode() + "配置站点：" + dispatchConfig.getSameParkPoint() + "，老站点：" + dispatchLog.getOldParkPoint() + "，新站点：" + parkPoint.getName();
                    }

                    if (!dispatchConfig.getDispatchDistance().equals(0) && dispatchLog.getIsValid().equals(1)) {
                        if (distance == null || distance < dispatchConfig.getDispatchDistance()) {
                            dispatchLog.setIsValid(0);
                            dispatchJudge = false;
                            /**添加到redismap*/
                            dispatchLog.setRemark(remark);
                            redisService.set(RedisConstant.REDIS_TER_BIKE_DISPATCH_DISTANCE_CHANGE_MAP, machine.getMachineNO(), String.valueOf(System.currentTimeMillis()));
                            redisService.add(RedisConstant.REDIS_TER_BIKE_DISPATCH + machine.getMachineNO(), JSONObject.toJSONString(dispatchLog), 3600 * 3);
                        } else {
                            dispatchLog.setIsValid(1);
                        }
                        remark = remark + "配置距离：" + dispatchConfig.getDispatchDistance() + "，实际距离：" + distance;
                        if (dispatchLog.getIsValid().equals(1)) {
                            remark = remark + "有效；";
                        } else {
                            remark = remark + "无效；";
                        }
                    }

                    if (dispatchJudge) {
                        isValid = dispatchLog.getIsValid();

                        /**判断订单时间*/
                        if (dispatchConfig.getRideTime() != null && dispatchConfig.getRideTime() != 0) {
                            state = WorkOrderConstant.state_SHZ;

                            String ordersAfterLastDispatchMachineKey = String.format(RedisConstant.ORDERS_AFTER_LAST_DISPATCH_MACHINE, machine.getMachineId());
                            int rideTimeSecond = dispatchConfig.getRideTime() * 60 * 60;
                            // 调度后产生订单时间动态配置缓存有效订单时长
                            redisService.add(ordersAfterLastDispatchMachineKey, StrPool.AT, rideTimeSecond);
                            log.info("记录调度后车辆({})有效订单", machine);
                        }

                        if (!state.equals(WorkOrderConstant.state_SHZ) || isValid.equals(0)) {
                            dispatchLog.setIsValid(isValid);
                            dispatchLog.setAuditTime(newTime);
                            state = WorkOrderConstant.state_WC;
                        } else {
                            dispatchLog.setIsValid(2);
                        }
                        dispatchLog.setRemark(remark);

                        /**
                         * 判断分区
                         */
                        GeoreMachine georeMachine = georeMachineService.getByMachineId(machine.getMachineId());
                        if (georeMachine != null) {
                            dispatchLog.setRegionId(georeMachine.getRegionId());
                        }

                        insert(dispatchLog);

                        // 更新工单状态
                        String workOrderId = this.endWork(machine.getMachineId(), dispatchLog.getDispatchLogId(), dispatchLog.getIsValid(), state, accountUser, remark);

                        /**订单条件缓存*/
                        if (state.equals(WorkOrderConstant.state_SHZ) && isValid.equals(1)) {
                            PowerChangeRedis powerChangeRedis = new PowerChangeRedis();
                            powerChangeRedis.setPowerChangeId(dispatchLog.getDispatchLogId());
                            powerChangeRedis.setWorkOrderId(workOrderId);
                            powerChangeRedis.setRideTime(dispatchConfig.getRideTime());
                            powerChangeRedis.setTime(newTime);

                            List<PowerChangeRedis> powerChangeList = new LinkedList<>();

                            /**判断是否存在审核中*/
                            String powerChangeRedisList = redisService.get(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machine.getMachineNO());
                            if (powerChangeRedisList != null) {
                                List<PowerChangeRedis> powerChangeLogs = new LinkedList<>();
                                try {
                                    powerChangeLogs = JSON.parseArray(powerChangeRedisList, PowerChangeRedis.class);
                                } catch (JSONException e) {
                                    redisService.del(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machine.getMachineNO());
                                }

                                if (CollUtil.isNotEmpty(powerChangeLogs)) {
                                    powerChangeList.addAll(powerChangeLogs);
                                }
                            }
                            powerChangeList.add(powerChangeRedis);

                            /**订单判断缓存*/
                            redisService.add(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machine.getMachineNO(), JSONObject.toJSONString(powerChangeList), (3600 * dispatchConfig.getRideTime()) + 1200);
                            log.info("批量添加调度缓存：" + powerChangeList + ";" + ((3600 * dispatchConfig.getRideTime()) + 1200));
                            /**二级缓存*/
                            redisService.set(RedisConstant.REDIS_TER_BIKE_DISPATCH_CHANGE_RIDE_MAP, machine.getMachineNO(), String.valueOf(System.currentTimeMillis()));
                            log.info("批量添加调度二级缓存：" + machine);
                        }
                        /**删除redis记录*/
                        redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH + machine.getMachineNO());

                        /**删除调度申请标识*/
                        redisService.del(RedisConstant.MACHINE_DISPATCH_APPLY_LOG + machine.getMachineNO());
                    }

                    /**修改最后借出时间*/
                    machineService.updateLastBorrowTime(machine.getMachineId());
                    /**投放车辆*/
                    Integer inside = null;
                    MachineStatus machineStatus = machineStatusService.getByMachineId(machine.getMachineId());
                    if (machineStatus != null) {
                        Double distance1;
                        ParkPoint parkPoint1 = dataService.getParkPoint(parkPointId);
                        // 圆形站点
                        if (parkPoint1.getParkPointType().equals(0)) {
                            distance1 = GeoUtil.getDistance(new Point(machineStatus.getLon(), machineStatus.getLat()), new Point(parkPoint1.getLo(), parkPoint1.getLa()));
                        } else {
                            List<Point> points = dataService.getParkList(parkPointId);
                            distance1 = GeoUtil.getDistance(new Point(machineStatus.getLon(), machineStatus.getLat()), points);
                        }
                        if (distance1 <= parkPoint1.getAllowRange()) {
                            inside = 1;
                        } else {
                            inside = 0;
                        }

                    }

                    Integer i = machineService.parkMachineInside(machine.getMachineId(), parkPoint.getParkPointId(), inside);
                    if (i == 0) {
                        machineService.put(new ParkMachine(parkPoint.getParkPointId(), machine.getMachineId(), inside));
                    }
                    machineService.put(new ParkMachine(parkPointId, machine.getMachineId(), inside));

                    /**删除批量调度redis数据，人员*/
                    String userDispatchMachineCache = RedisConstant.REDIS_BATCH_DISPATCH + accountUser.getAccountUserId();
                    redisService.delToList(userDispatchMachineCache, machine.getUserCode());
                    /**删除批量调度redis数据，区域*/
                    String areaDispatchMachineCache = RedisConstant.REDIS_BATCH_DISPATCH_AREA + machine.getAccountId();
                    redisService.delToList(areaDispatchMachineCache, machine.getUserCode());
                }

                /**上锁*/
                dispatchLock(machine, "调度完成自动上锁");

                // 根据条件修改审核状态
                updateAudit(machine.getMachineId(), dispatchLog, machine.getAccountId(), machine.getMachineNO());
            } else {
                /**删除已被他人调度的车辆，人员*/
                String userDispatchMachineCache = RedisConstant.REDIS_BATCH_DISPATCH + accountUser.getAccountUserId();
                redisService.delToList(userDispatchMachineCache, machine.getUserCode());
                /**删除已被他人调度的车辆，区域*/
                String areaDispatchMachineCache = RedisConstant.REDIS_BATCH_DISPATCH_AREA + machine.getAccountId();
                redisService.delToList(areaDispatchMachineCache, machine.getUserCode());
            }
            redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH_USER_CODE + machine.getUserCode());
        }

    }

    @Override
    public void dispatchLock(Machine machine, String remark) {

        // 排除小红羚单车指定区域的开锁业务
        if ((machine.getMachineType().equals(MachineTypeConstant.BIKE) && machineFunctionService.checkIsSendControl(machine.getMachineId()))|| machine.getMachineType().equals(MachineTypeConstant.ELECTRIC_BIKE)) {
       // if (!(accountProperties.getXhlAccountIds().contains(machine.getAccountId()) && machine.getMachineType().equals(MachineTypeConstant.BIKE))) {
            /**上锁*/
            String serNO = UUID.randomUUID().toString();
            terControlService.commonControl(new CommonControlParamBO(serNO, machine, ControlType.MACHINE_CONTROL_LOCK, remark));
        }
    }

    /**
     * 根据条件修改审核状态中的为无效
     *
     * @param machineId   车辆id
     * @param dispatchLog 当前调度记录
     * @param accountId   区域id
     * @param machineNO   设备编号
     */
    private void updateAudit(Integer machineId, DispatchLog dispatchLog, Integer accountId, String machineNO) {
        if (dispatchLog == null || dispatchLog.getDispatchLogId() == null) {
            log.info("当前调度记录id为空,machineId={},accountId={},machineNO={}", machineId, accountId, machineNO);
            return;
        }
        DispatchConfig dispatchConfig = dataService.getDispatch(accountId);
        if (dispatchConfig == null || dispatchConfig.getRideTime() == null || dispatchConfig.getRideTime() == 0) {
            return;
        }
        List<PowerChangeRedis> powerChangeRedisList = new LinkedList<>();
        String redisDispatch;
        try {
            redisDispatch = redisService.get(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machineNO);
            if (redisDispatch != null) {
                powerChangeRedisList = JSON.parseArray(redisDispatch, PowerChangeRedis.class);
            }
        } catch (Exception e) {
            redisService.del(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machineNO);
        }
        // 无效记录
        List<Integer> invalidDispatchLogIdList = new ArrayList<>();
        // 有效记录
        List<Integer> validDispatchLogIdList = new ArrayList<>();
        // 查询当前车辆审核中的调度记录
        List<DispatchLog> underReviewDispatchLogs = dispatchLogDao.getUnderReviewByMachineId(machineId);

        for (DispatchLog underReviewDispatchLog : underReviewDispatchLogs) {
            Integer oldDispatchLogId = underReviewDispatchLog.getDispatchLogId();
            if (oldDispatchLogId.equals(dispatchLog.getDispatchLogId())) {
                // 当前调度记录不操作
                continue;
            }
            // 判断审核中调度记录是否符合规定时间内未产生有效骑行订单条件，符合就置为失效
            String finishTime = underReviewDispatchLog.getFinishTime();
            Date afterLatestTime = rideLogService.getAfterLatest(finishTime, machineId);
            if (afterLatestTime == null || DateUtil.between(DateUtil.parse(finishTime, "yyyy-MM-dd HH:mm:ss"), afterLatestTime, DateUnit.HOUR) < dispatchConfig.getRideTime()) {
                invalidDispatchLogIdList.add(oldDispatchLogId);
            } else {
                validDispatchLogIdList.add(oldDispatchLogId);
            }

        }

        if (!invalidDispatchLogIdList.isEmpty()) {
            // 再次调度修改待审核状态下的记录为失败
            String remark = ",当前车辆产生新的调度审核,未产生有效骑行订单,自动审核无效";
            dispatchLogDao.updateAuditToInvalidByDispatchLogIdList(invalidDispatchLogIdList, WorkOrderConstant.isValid, remark);
            workOrderService.updateAuditToInvalidByBusinessNOList(invalidDispatchLogIdList, WorkOrderConstant.isValid, WorkOrderConstant.state_WC, remark);
        }
        if (!validDispatchLogIdList.isEmpty()) {
            // 再次调度修改待审核状态下的记录为有效
            String remark = ",当前车辆产生新的调度审核,产生有效骑行订单,自动审核有效";
            dispatchLogDao.updateAuditToInvalidByDispatchLogIdList(validDispatchLogIdList, WorkOrderConstant.valid, remark);
            workOrderService.updateAuditToInvalidByBusinessNOList(validDispatchLogIdList, WorkOrderConstant.valid, WorkOrderConstant.state_WC, remark);
        }
        if (!powerChangeRedisList.isEmpty()) {
            // 去除已自动审核的调度缓存
            List<PowerChangeRedis> newPowerChangeRedis = new ArrayList<>();
            for (PowerChangeRedis powerChangeRedis : powerChangeRedisList) {
                if (invalidDispatchLogIdList.contains(powerChangeRedis.getPowerChangeId()) || validDispatchLogIdList.contains(powerChangeRedis.getPowerChangeId())) {
                    continue;
                }
                newPowerChangeRedis.add(powerChangeRedis);
            }
            if (newPowerChangeRedis.isEmpty()) {
                redisService.del(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machineNO);
            } else {
                redisService.add(RedisConstant.REDIS_TER_DISPATCH_CHANGE_RIDE + machineNO, JSONObject.toJSONString(newPowerChangeRedis), (3600 * dispatchConfig.getRideTime()) + 1200);
            }
        }
    }


    @Override
    public String endWork(Integer machineId, Integer dispatchLogId, Integer isValid, Integer state, AccountUser accountUser, String remark) {
        // 只有一笔调度工单
        String workOrderId = null;

        // 获得车辆待办工单
        List<WorkOrderFinishing> workOrderFinishingList = workOrderFinishingService.getByWorkMachineIdState(machineId, WorkOrderConstant.state_LQ);

        for (WorkOrderFinishing workOrderFinishing : workOrderFinishingList) {
            // 调度完成删除待办的挪车工单
            if (workOrderFinishing.getWorkType().equals(WorkOrderConstant.workType_NC)) {
                workOrderFinishingService.del(workOrderFinishing.getWorkOrderId());
                workOrderService.del(workOrderFinishing.getWorkOrderId());

                LogUtil.info(String.format("[DispatchLogServiceImpl][endWork][调度完成删除挪车工单：%s]", workOrderFinishing));
            }

            if (workOrderFinishing.getWorkType().equals(WorkOrderConstant.workType_DD)) {
                workOrderId = workOrderFinishing.getWorkOrderId();

                // 结束待办工单
                workOrderFinishingService.del(workOrderId);

                // 更新已完成工单
                WorkOrder workOrder = new WorkOrder();
                workOrder.setWorkOrderId(workOrderId);
                if (null != accountUser) {
                    workOrder.setGetUserId(accountUser.getAccountUserId());
                    workOrder.setGetUserName(accountUser.getName());
                }
                workOrder.setBusinessNO(dispatchLogId);
                workOrder.setState(state);
                workOrder.setFinishTime(DateTimeUtil.getNowTime());
                workOrder.setIsValid(isValid);
                workOrder.setRemark(remark);
                workOrderService.update(workOrder);

                LogUtil.info(String.format("[DispatchLogServiceImpl][endWork][结果：%s]", workOrderFinishing));
            }
        }
        return workOrderId;
    }

    @Override
    public DispatchLog getById(Integer dispatchLogId) {

        DispatchLog dispatchLog = dispatchLogDao.getById(dispatchLogId);

        if (dispatchLog != null) {
            /**计算挪车距离*/
            Integer distance = historyService.getMileageByMachineNOAndTime(dispatchLog.getMachineNO(), dispatchLog.getDispatchTime(), dispatchLog.getFinishTime());
            dispatchLog.setDistance(distance == null ? 0 : distance);

            if (dispatchLog.getAuditorId() == null || dispatchLog.getAuditorId().equals(WorkOrderConstant.sys_auditor)) {
                dispatchLog.setAuditorName(WorkOrderConstant.sys_auditorName);
            } else if (dispatchLog.getAuditorId() != null) {
                AccountUser accountUser = accountUserService.getById(dispatchLog.getAuditorId());
                dispatchLog.setAuditorName(accountUser.getName());
            }
        }

        return dispatchLog;
    }

    @Override
    public List<DispatchLog> getByIds(List<Integer> dispatchLogIds) {
        return dispatchLogDao.getByIds(StringUtil.getListString(dispatchLogIds));
    }

    @Override
    public List<DispatchLog> getByMachineIdTime(Integer machineId, String time, Integer isValid) {
        Map<String, Object> map = new HashMap<>();
        map.put("machineId", machineId);
        map.put("time", time);
        return dispatchLogDao.getByMachineIdTime(map);
    }

    @Override
    public void audit(Integer dispatchId, Integer isValid, String remark, String auditTime) {
        DispatchLog dispatchLog = new DispatchLog();
        dispatchLog.setDispatchLogId(dispatchId);
        dispatchLog.setIsValid(isValid);
        dispatchLog.setRemark(remark);
        dispatchLog.setAuditTime(auditTime);
        dispatchLogDao.update(dispatchLog);
    }

    @Override
    @Transactional("logTransactionManager")
    public void update(MainLogAuditVo vo) {
        DispatchLog dispatchLogDb = dispatchLogDao.getById(vo.getLogId());
        if (dispatchLogDb == null) {
            return;
        }
        // 要修改为无效，但当前已是无效，则返回
        if (Objects.equals(vo.getIsValid(), 0)
                && Objects.equals(dispatchLogDb.getIsValid(), 0)) {
            return;
        }
        // 要修改为有效，但当前已是有效，并且不修改绩效值，则返回
        if (Objects.equals(vo.getIsValid(), 1)
                && Objects.equals(dispatchLogDb.getIsValid(), 1)
                && vo.getPerformance() == null) {
            return;
        }

        // 运维绩效-修改有效性逻辑
        if (!Objects.equals(vo.getIsValid(), dispatchLogDb.getIsValid())) {
            dispatchLogUpdate(vo, dispatchLogDb);
        }

        // 无效改有效：插入0分记录
        if (Objects.equals(vo.getIsValid(), 1)) {
            //判断绩效开关是否打开
            AccountConfigExt performanceSwitch = accountConfigExtService.getParamKey(dispatchLogDb.getAccountId(), AccountConfigExtConstant.DISPATCH_PERFORMANCE);
            if (performanceSwitch != null && Objects.equals(performanceSwitch.getParamValue(), "1")) {
                // 如果开关打开了
                // 这个判断一下是否同时修改绩效值，如果有绩效值，则生成（或修改：如果已有绩效记录）一条绩效记录，并设置绩效值为当前传入的绩效值
                // 如果没有传绩效值，则是根据绩效配置生成绩效记录
                performanceService.generatePerformance(dispatchLogDb, vo.getPerformance());
            }
        }

        // 有效改无效：删除现有记录
        if (Objects.equals(vo.getIsValid(), 0)) {
            performanceService.removePerformance(dispatchLogDb.getDispatchLogId());
        }
    }

    private void dispatchLogUpdate(MainLogAuditVo vo, DispatchLog dispatchLogDb) {
        AccountUser loginUser = LoginUserContextHolder.getLoginUser();
        dispatchLogDb.setAuditorId(loginUser.getAccountUserId());
        dispatchLogDb.setIsValid(vo.getIsValid());
        dispatchLogDb.setAuditTime(DateTimeUtil.getNowTime());
        if (StrUtil.isNotBlank(vo.getRemark())) {
            String remark = String.format("[%s]%s-%s", DateTimeUtil.getNowTime(), loginUser.getName(), vo.getRemark());
            dispatchLogDb.setRemark(remark);
        }
        // 插入车辆操作日志
        machineOpLogService.insertSingle(MachineOpLog.builder()
                .accountId(dispatchLogDb.getAccountId())
                .machineId(dispatchLogDb.getMachineId())
                .machineNO(dispatchLogDb.getMachineNO())
                .userCode(dispatchLogDb.getUserCode())
                .opType(String.format("变更状态[%d->%d]", dispatchLogDb.getIsValid(), vo.getIsValid()))
                .operation("调度")
                .opUser(loginUser.getName())
                .opUserPhone(loginUser.getPhone())
                .opPlatform(OperationPlatform.MAINTAIN.code)
                .result(true)
                .opTime(LocalDateTime.now())
                .build()
        );
        dispatchLogDao.update(dispatchLogDb);
    }

    @Override
    public Integer workOrder(String userCode) throws ParseException {
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }
//        DispatchConfig dispatchConfig = dispatchConfigService.getByAccountId(machine.getAccountId());
        DispatchConfig dispatchConfig = dataService.getDispatch(machine.getAccountId());
        if (dispatchConfig == null) {
            return 0;
        }
        if (StringUtils.isBlank(dispatchConfig.getCheckedCondition())) {
            return 0;
        }
        // 选中的条件 根据页面下标而来
        List<String> checkedCondition = Arrays.stream(dispatchConfig.getCheckedCondition().split(",")).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(checkedCondition)) {
            return 0;
        }

        List<Integer> errorCode = new ArrayList<>();

        // 判断调度闲置时间
        if (checkedCondition.contains("0")) {
            // 闲置时长 如果未配置就是0
            Integer dispatchLeave = Optional.ofNullable(dispatchConfig.getDispatchLeave()).orElse(0);
            Integer time = DateTimeUtil.getHours(StringUtils.defaultIfBlank(machine.getLastBorrowTime(), DateTimeUtil.getNowTime()), DateTimeUtil.getNowTime());
            if (dispatchLeave > time) {
                errorCode.add(4);
            }
        }
        if (checkedCondition.contains("1") || checkedCondition.contains("2") || checkedCondition.contains("3")) {
            List<DispatchLog> dispatchLogs = getByMachineIdTime(machine.getMachineId(), null, 1);
            List<RideLog> rideLogs;
            if (CollectionUtils.isNotEmpty(dispatchLogs)) {
                rideLogs = rideLogService.getMachineIdStartTime(machine.getMachineId(), dispatchLogs.get(0).getDispatchTime(), null);
            } else {
                rideLogs = rideLogService.getMachineIdStartTime(machine.getMachineId(), null, DateTimeUtil.getNowTime());
            }
            if (checkedCondition.contains("1")) {
                // 上次调度后产生有效订单
                boolean needRideOrder = Objects.equals(1, dispatchConfig.getRide());
                if (needRideOrder && CollectionUtils.isEmpty(rideLogs)) {
                    errorCode.add(1);
                }
            }
            if (checkedCondition.contains("2")) {
                Integer logTime = Optional.ofNullable(dispatchConfig.getLogTime()).orElse(0);
                if (logTime > 0) {
                    List<DispatchLog> dispatchLogList = getByMachineIdTime(machine.getMachineId(), DateTimeUtil.getMinsAgo(logTime), 1);
                    if (CollectionUtils.isNotEmpty(dispatchLogList)) {
                        errorCode.add(3);
                    }
                }
            }
            if (checkedCondition.contains("3")) {
                Integer rideDistance = Optional.ofNullable(dispatchConfig.getRideDistance()).orElse(0);
                if (rideDistance > 0) {
                    double distanceCount = 0;
                    for (RideLog rideLog : rideLogs) {
                        distanceCount = distanceCount + rideLog.getMileage();
                    }
                    if ((distanceCount * 1000) < dispatchConfig.getRideDistance()) {
                        errorCode.add(2);
                    }
                }
            }
        }
        if (dispatchConfig.matchOne()) {
            if (checkedCondition.size() == errorCode.size()) {
                return errorCode.get(0);
            }
        } else {
            if (CollectionUtils.isNotEmpty(errorCode)) {
                return errorCode.get(0);
            }
        }
        return 0;
    }

    @Override
    public List<DispatchLog> getDispatchLogIds(List<Integer> dispatchLogIdList) {

        List<DispatchLog> dispatchLogList = dispatchLogDao.selectDispatchLogIds(dispatchLogIdList);

        for (DispatchLog dispatchLog : dispatchLogList) {
            /* 计算挪车距离 */
            Integer distance = historyService.getMileageByMachineNOAndTime(dispatchLog.getMachineNO(), dispatchLog.getDispatchTime(), dispatchLog.getFinishTime());
            dispatchLog.setDistance(distance);

            if (dispatchLog.getAuditorId() == null || dispatchLog.getAuditorId().equals(WorkOrderConstant.sys_auditor)) {
                dispatchLog.setAuditorName(WorkOrderConstant.sys_auditorName);
            } else {
                AccountUser accountUser = accountUserService.getById(dispatchLog.getAuditorId());
                dispatchLog.setAuditorName(accountUser.getName());
            }
        }

        return dispatchLogList;
    }

    @Override
    public void updateFistOrderTimeAndAfterValidOrder(Integer machineId) {
        dispatchLogDao.updateFistOrderTimeAndAfterValidOrder(machineId);
    }

    @Override
    public void delCache(String userCode) {
        AccountUser loginUser = LoginUserContextHolder.getLoginUser();
        String dispatchUserCodeKey = RedisConstant.REDIS_TER_BIKE_DISPATCH_USER_CODE + userCode;
        String machineNO = redisService.get(dispatchUserCodeKey);

        String dispatchLogString = redisService.get(RedisConstant.REDIS_TER_BIKE_DISPATCH + machineNO);
        Integer accountUserId = loginUser.getAccountUserId();
        Integer accountId = loginUser.getAccountId();
        if (StrUtil.isNotBlank(dispatchLogString)) {
            DispatchLog dispatchLogCache = JSONObject.parseObject(dispatchLogString, DispatchLog.class);
            accountUserId = dispatchLogCache.getUserMainId();
            accountId = dispatchLogCache.getAccountId();
        }

        /**删除redis记录*/
        redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH + machineNO);

        /**删除批量redis记录,人员*/
        redisService.delToList(RedisConstant.REDIS_BATCH_DISPATCH + accountUserId, userCode);
        /**删除批量redis记录,区域*/
        redisService.delToList(RedisConstant.REDIS_BATCH_DISPATCH_AREA + accountId, userCode);

        /**删除调度申请标识*/
        redisService.del(RedisConstant.MACHINE_DISPATCH_APPLY_LOG + machineNO);

        redisService.del(dispatchUserCodeKey);
    }

    @Override
    public void batchDelCache(List<String> userCodes) {
        userCodes.forEach(this::delCache);
    }

}